#pragma once 

#include <iostream>
#include <queue>
#include <pthread.h>

template <class T>
class ThreadPool 
{
  private:
    int _num;  //线程池中线程数量
    std::queue<T> _q;  //给线程池派发任务的地点
    pthread_mutex_t lock;
    pthread_cond_t cond;
    
  public:
    ThreadPool(int num): _num(num)
    {
      pthread_mutex_init(&lock, nullptr);
      pthread_cond_init(&cond, nullptr);
    }
    void PopTask(T *out)  //取任务
    {
      *out = _q.front();
      _q.pop();
    }
    void Lock()
    {
      pthread_mutex_lock(&lock);
    }
    void UnLock()
    {
      pthread_mutex_unlock(&lock);
    }
    bool IsEmpty()
    {
      return _q.size() == 0;
    }
    //如果Routine是类内成员方法，参数包含this指针
    //不符合线程回调函数的一个参数，所以需要定义为static修饰
    //static修饰带成员方法，只能访问static属性，或者通过对象的方式来进行内部方法属性带访问！这里就是将this指针作为参数来解决的！
    static void *Routine(void *args)
    {
      pthread_detach(pthread_self()); //线程分离
      ThreadPool *tp = (ThreadPool*)args;

      while(true)
      {
        tp->Lock();
        //1、检测是否有任务
        while(tp->IsEmpty())
        {
          //等待任务
          pthread_cond_wait(&(tp->cond), &(tp->lock));
        }
        //2、取任务的过程
        T t;
        tp->PopTask(&t);
       
        tp->UnLock();
        //3、处理任务
        t.run();
      }
    }
    void InitThreadPool()
    {
      for(int i = 0; i < _num; i++)
      {
        pthread_t tid;
        pthread_create(&tid, nullptr, Routine, this);
      }
    }
    void PushTask(const T &in)
    {
      pthread_mutex_lock(&lock);
      _q.push(in);
      pthread_cond_signal(&cond);
      pthread_mutex_unlock(&lock);
    }

    ~ThreadPool()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&cond);
    }
};
